library(fields)
library(deSolve)

#################### functions for drawing phase planes and trajectories ###############

# draw phase plane
# input:
#	ode.sys:  ode system
#	ode.event, ode.root: event and root function for deSolve in the case that ode.sys is discountinous
# 	nullcline: function to compute nullcline
#	params: params for ode system
#	xrange: c(xmin,xmax) of the graph
#	yrange: c(ymin,ymax) of the graph
#	xstep(ystep): the x(y) distance between two vector tails
#	x.ini, y.ini: initial conditions of the system
#	times: time sequence of trajectories
draw.phase.plane <- function(ode.sys, ode.event, ode.root, 
					nullcline, params, 
					xrange, yrange, xstep, ystep,
					xlabel, ylabel, 
					x.ini, y.ini, times) {

	####### draw vector field #######
	# compute the tails of vectors
	x <- seq(xrange[1], xrange[2], xstep)
	y <- seq(yrange[1], yrange[2], ystep)
	vec.tail.x <- rep(x, time = length(y))
	vec.tail.y <- rep(y, each = length(x))

	# compute the directions of vectors
	n.vecs <- length(vec.tail.x)
	vec.dir.x <- rep(0, n.vecs)
	vec.dir.y <- rep(0, n.vecs)

	for (i in 1:n.vecs) {
		dir <- ode.sys(0, c(vec.tail.x[i],vec.tail.y[i]), params)[[1]]
		vec.dir.x[i] <- dir[1]
		vec.dir.y[i] <- dir[2]
	}

	# draw
	dev.new()
	plot(vec.tail.x, vec.tail.y, type='n', xlab=xlabel, ylab=ylabel)
	arrow.plot(
		vec.tail.x, vec.tail.y,
		vec.dir.x, vec.dir.y,
		arrow.ex=.05, length=.05, col='blue', lwd=1,
		true.angle = TRUE)

	####### draw nullclines ######
	# compute nullcline
	x <- seq(xrange[1], xrange[2], xstep/10)
	dx.nc.y <- rep(0, length(x))
	dy.nc.y <- rep(0, length(x))
	
	for (i in 1:length(x)) {
		y <- nullcline(x[i], params)
		dx.nc.y[i] <- y[1]
		dy.nc.y[i] <- y[2]
	}
	
	# draw
	lines(x, dx.nc.y, col='red')
	lines(x, dy.nc.y, col='red')

	####### draw trajectories #######
	n.starts = length(x.ini)
	points(x.ini, y.ini)
	for (i in 1:n.starts) {
		traj <- ode(y = c(y1=x.ini[i],y2=y.ini[i]),
				func = ode.sys,
				times = times, 
				parms = params,
				events=list(func=ode.event, root=TRUE), rootfun=ode.root)
		lines(traj[,2], traj[,3], col='black')
	}
}

# draw trajectory over time
# input:
#	ode.sys: system of ODEs
#	params: parameters for ode.sys
#	x.ini, y.ini: initial condition
#	times: time steps 
#	xlabel, ylabel: names of the first and the second depedent variables
draw.trajectory.over.time <- function(ode.sys, ode.root, ode.event, params, 
										x.ini, y.ini, times,
										xlabel, ylabel) {
	for (i in 1:length(x.ini)) {
		traj <- ode(y = c(y1=x.ini[i],y2=y.ini[i]),
				func = ode.sys,
				times = times, 
				parms = params,
				events=list(func=ode.event, root=TRUE), rootfun=ode.root)
				colnames(traj) <- c("t", xlabel, ylabel)
		dev.new()
		plot(traj, col='black')
	}
}
